package excel;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Properties;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFFont;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.util.CellRangeAddress;
import org.jboss.logging.Logger;
import report.ReportData;

public class ExcelReportBuilder {

    private HSSFSheet sheet;
    private HSSFWorkbook workbook;
    private static String SAVE_PATH = "";
    private final int DATE_ROW = 1;
    private final int TITLE_ROW = 3;
    private final int HEADER_ROW = 5;
    private final int START_DATA_ROW = 6;
    private final int START_DATA_COLUMN = 1;
    private final short HEADER_FOREGROUND_COLOR = IndexedColors.GREY_25_PERCENT.index;
    private static String DATE_FORMAT = "HH:mm dd/MM/yyyy";
    public static final String configFile = "excelreportbuilder.properties.ini";
    public static boolean configLoaded = false;
    private HSSFCellStyle TAN_STYLE;
    private HSSFCellStyle LIGHT_YELLOW_STYLE;
    private static long deleteTimeout = 300000L;

    public static Properties loadProperties() {
        try {
            Properties props = new Properties();
            props.load(new FileInputStream(ExcelReportBuilder.class.getResource(configFile).getPath()));
            return props;
        } catch (Exception e) {
            Logger.getLogger(ExcelReportBuilder.class).warn(e.getMessage());
        }
        return null;
    }

    public static void saveProperties(Properties props) {
        try {
            props.store(new FileOutputStream(ExcelReportBuilder.class.getResource(configFile).getPath()), null);
        } catch (Exception e) {
            Logger.getLogger(ExcelReportBuilder.class).warn(e.getMessage());
        }
    }

    private static void loadConfig() {
        try {
            Properties props = new Properties();
            props.load(new FileInputStream(ExcelReportBuilder.class.getResource(configFile).getPath()));
            DATE_FORMAT = props.getProperty("DATE_FORMAT", DATE_FORMAT);
            String tmp_SAVE_PATH = SAVE_PATH;
            SAVE_PATH = props.getProperty("SAVE_PATH", SAVE_PATH);
            File savePath = new File(SAVE_PATH);
            savePath.mkdirs();
            if (!savePath.exists()) {
                SAVE_PATH = tmp_SAVE_PATH;
            }
            configLoaded = true;
        } catch (Exception e) {
            Logger.getLogger(ExcelReportBuilder.class).warn(e.getMessage());
        }
    }

    private static void deleteOldReports() {
        if (!SAVE_PATH.equals("")) {
            File directory = new File(SAVE_PATH);
            File[] reports = directory.listFiles();
            long currentTime = new Date().getTime();
            long createTime;
            for (int i = 0; i < reports.length; i++) {
                createTime = reports[i].lastModified();
                if ((currentTime - createTime) > deleteTimeout) {
                    reports[i].delete();
                }
            }
        }
    }

    public static String buildReport(ReportData report) {
        if (!configLoaded) {
            loadConfig();
        }
        deleteOldReports();
        ExcelReportBuilder builder = new ExcelReportBuilder();
        builder.setDate(report.getDate());
        builder.setTitle(report.getTitle(), report.getHeaders().size());
        builder.setHeaders(report.getHeaders());
        builder.fillData(report.getData());
        return builder.save();
    }

    private ExcelReportBuilder() {
        workbook = new HSSFWorkbook();
        sheet = workbook.createSheet("Report");
    }

    private void setDate(Date date) {
        HSSFRow row = sheet.createRow(DATE_ROW);
        row.createCell(1).setCellValue("Date:");
        HSSFCell dateCell = row.createCell(2);
        SimpleDateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT);
        dateCell.setCellValue(dateFormat.format(date));
    }

    private void fillData(ArrayList data) {
        for (int i = 0; i < data.size(); i++) {
            AddItem((ArrayList) data.get(i));
        }
    }

    private void setHeaders(ArrayList headers) {
        addCell(HEADER_ROW, START_DATA_COLUMN, "№", getHeaderStyle());
        for (int i = 0; i < headers.size(); i++) {
            addCell(HEADER_ROW, START_DATA_COLUMN + i + 1, headers.get(i), getHeaderStyle());
        }
    }

    private HSSFCellStyle getTitleStyle() {
        HSSFCellStyle result = workbook.createCellStyle();
        result.setVerticalAlignment(HSSFCellStyle.ALIGN_CENTER);
        result.setAlignment(HSSFCellStyle.ALIGN_CENTER);
        HSSFFont font = workbook.createFont();
        font.setFontHeightInPoints((short) 25);
        result.setFont(font);
        return result;
    }

    private HSSFCellStyle getHeaderStyle() {
        HSSFCellStyle result = workbook.createCellStyle();
        result.setBorderBottom(HSSFCellStyle.BORDER_MEDIUM);
        result.setBorderLeft(HSSFCellStyle.BORDER_MEDIUM);
        result.setBorderRight(HSSFCellStyle.BORDER_MEDIUM);
        result.setBorderTop(HSSFCellStyle.BORDER_MEDIUM);
        result.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
        result.setFillForegroundColor(HEADER_FOREGROUND_COLOR);
        HSSFFont font = workbook.createFont();
        font.setFontHeightInPoints((short) 12);
        result.setFont(font);
        return result;
    }

    private short getItemColor() {
        if (getDataRowIndex() % 2 == 0) {
            return IndexedColors.TAN.index;
        } else {
            return IndexedColors.LIGHT_YELLOW.index;
        }
    }

    private HSSFCellStyle getItemStyle() {
        if (getDataRowIndex() % 2 == 0) {
            if (TAN_STYLE == null) {
                TAN_STYLE = workbook.createCellStyle();
                TAN_STYLE.setBorderBottom(HSSFCellStyle.BORDER_THIN);
                TAN_STYLE.setBorderLeft(HSSFCellStyle.BORDER_THIN);
                TAN_STYLE.setBorderRight(HSSFCellStyle.BORDER_THIN);
                TAN_STYLE.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
                TAN_STYLE.setFillForegroundColor(getItemColor());
            }
            return TAN_STYLE;
        } else {
            if (LIGHT_YELLOW_STYLE == null) {
                LIGHT_YELLOW_STYLE = workbook.createCellStyle();
                LIGHT_YELLOW_STYLE.setBorderBottom(HSSFCellStyle.BORDER_THIN);
                LIGHT_YELLOW_STYLE.setBorderLeft(HSSFCellStyle.BORDER_THIN);
                LIGHT_YELLOW_STYLE.setBorderRight(HSSFCellStyle.BORDER_THIN);
                LIGHT_YELLOW_STYLE.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
                LIGHT_YELLOW_STYLE.setFillForegroundColor(getItemColor());
            }
            return LIGHT_YELLOW_STYLE;
        }
    }

    private void setTitle(String title, int headerSize) {
        sheet.addMergedRegion(
                new CellRangeAddress(TITLE_ROW, TITLE_ROW,
                START_DATA_COLUMN, START_DATA_COLUMN + headerSize));
        addCell(TITLE_ROW, START_DATA_COLUMN, title, getTitleStyle());
    }
    private int dataRowIndex = 0;

    private int getDataRowIndex() {
        return dataRowIndex;
    }

    private void incDataRowIndex() {
        dataRowIndex++;
    }

    private HSSFRow getRow(int rowIndex) {
        HSSFRow result = sheet.getRow(rowIndex);
        if (result == null) {
            result = sheet.createRow(rowIndex);
        }
        result.setHeightInPoints(-1);
        return result;
    }

    public void AddItem(ArrayList item) {
        addCell(START_DATA_COLUMN, new Integer(getDataRowIndex() + 1), getItemStyle());
        for (int i = 0; i < item.size(); i++) {
            addCell(START_DATA_COLUMN + i + 1, item.get(i), getItemStyle());
        }
        incDataRowIndex();
    }

    private void addCell(int columnIndex, Object value, HSSFCellStyle style) {
        addCell(START_DATA_ROW + getDataRowIndex(), columnIndex, value, style);
    }

    private void addCell(int rowIndex, int columnIndex, Object value, HSSFCellStyle style) {
        HSSFCell cell = getRow(rowIndex).createCell(columnIndex);
        sheet.autoSizeColumn(cell.getColumnIndex());
        cell.setCellValue(parseValue(value));
        cell.setCellStyle(style);
    }

    private String parseValue(Object value) {
        if (value == null) {
            return "";
        }
        if (value instanceof Date) {
            return new SimpleDateFormat(DATE_FORMAT).format(value);
        }
        return String.valueOf(value);
    }

    public String save() {
        FileOutputStream fos = null;
        String reportPath = SAVE_PATH + getReportName();
        File reportFile = new File(reportPath);
        try {
            fos = new FileOutputStream(reportFile);
            workbook.write(fos);
        } catch (IOException e) {
            Logger.getLogger(getClass()).error(e.getMessage());
        } finally {
            if (fos != null) {
                try {
                    fos.flush();
                    fos.close();
                } catch (IOException e) {
                    Logger.getLogger(getClass()).error(e.getMessage());
                }
            }
            return reportPath;
        }
    }
    int genCounter = 0;

    private synchronized String getReportName() {
        String plainText = String.valueOf(genCounter)
                + String.valueOf(System.nanoTime());
        MessageDigest md;
        String result;
        DateFormat format = new SimpleDateFormat("MM-dd-yyyy");
        String date = format.format(new Date());
        result = date + "_report_";
        try {
            md = MessageDigest.getInstance("MD5");
            md.update(plainText.getBytes());
            BigInteger bi = new BigInteger(1, md.digest());
            result += bi.toString(16);
        } catch (NoSuchAlgorithmException e) {
            result = result.substring(0, result.length() - 1);
        }
        return result + ".xls";
    }
}
